package gamecore;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;

/**
 * @author Alberola Gustavo Alejandro
 * Fecha de creación: 09 de Julio de 2009
 *
 * Nucleo de ejecución para video juegos.
 */
abstract public class GameCore implements Runnable {

	//==============================================================================================
	//	ATRIBUTOS
	//==============================================================================================
	/**Hilo de ejecución del GameCore*/
	private Thread gameCore;
	/**Indica si se muestran o no las estadísticas de ejecución en pantalla*/
	private boolean showStadistics;

	//------------------------------------------------------------------------------------------------
	//ATRIBUTOS DE CONTROL DE ESTADO DEL CORE

	/**Indica si el GameCore se encuentra o no ejecutandose*/
	private volatile boolean coreRunning;
	/**Indica si el GameCore se encuentra o no pausado*/
	private volatile boolean corePaused;
	/**Indica si el juego se encuentra corriendo (false equivaldría a un Game Over)*/
	private volatile boolean gameRunning;
	/**Indica si el juego se encuentra pausado*/
	private volatile boolean gamePaused;

	//==============================================================================================
	//	CONSTRUCTORES
	//==============================================================================================
	/**
	 * Nucleo de ejecución. Requiere que se especifique un Canvas y un Clock específicos.
	 * @param canvas
	 * @param clock
	 */
	public GameCore (){		
	}

	//==============================================================================================
	//	GETTERS
	//==============================================================================================
	/**Indica si el GameCore se encuentra pausado.
	 * @return*/
	public boolean isCorePaused() {	return corePaused; }
	/**Indica si el GameCore se enuentra en ejecución.
	 * @return*/
	public boolean isCoreRunning() { return coreRunning; }
	/**Indica si el juego se encuentra pausado
	 * @return*/
	public boolean isGamePaused() {	return gamePaused; }
	/**Indica si el juego se encuentra en ejecución
	 * @return*/
	public boolean isGameRunning() { return gameRunning; }

	//==============================================================================================
	//	MÉTODOS DE ACTUALIZACIÓN DEL ESTADO DEL CORE
	//==============================================================================================
	/**Inicializa la ejecución del GameCore. Este método puede generar excepciones, en caso de que
	 * alguno de los elementos requeridos no se haya inicializado.*/
	public void startCore (){
		//Verificamos que el GameCore no se encuentre actualmente en ejecución
		if ( gameCore == null || !coreRunning ){
			gameCore = new Thread(this);//Obtenemos el Thread de la clase GameCore
			gameCore.start();			//Ejecutamos el Thread (esto llama al método run() )
		}
	}
	/**Detiene la ejecución del GameCore.*/
	public void stopCore (){ coreRunning = false; }
	/**Resume la ejecución del GameCore, luego de haberlo pausado.*/
	public void resumeCore (){ corePaused = false; }
	/**Pausa la ejecución del GameCore.*/
	public void pauseCore (){ corePaused = true; }
	/**Inicializa el juego*/
	public void startGame (){ gameRunning = true; }
	/**Finaliza el juego (Game Over)*/
	public void stopGame (){ gameRunning = false; }
	/**Pausa la ejecución del juego*/
	public void resumeGame (){ gamePaused = false; }
	/**Resume la ejecución del juego, luego de haerlo pausado.*/
	public void pauseGame (){ gamePaused = true; }
	//==============================================================================================
	//	LÓGICA DE EJECUCIÓN DEL CORE
	//==============================================================================================
	/**
	 * Cuando se inicializa el GameCore, este es el método encargado de controlar la lógica de ejecución.
	 */
	public void run() {
		System.out.println("======================================================================");
		System.out.println("Core start");
		System.out.println("======================================================================");
		//Se establecen los estados del GameCore antes de inicializarlo
		gamePaused = false;	//Juego no pausado
		gameRunning = true; //Juego corriendo
		corePaused = false; //GameCore no pausado
		coreRunning = true; //GameCore corriendo

		//Mientras que no se solicite la terminación del core ( stopCore() ), el mismo seguirá ejecutándose
		while ( coreRunning ){
			//Si el core se encuentra pausado, se saltea la llamada a los métodos de actualización del juego
			if ( !corePaused ){
				gameUpdate();				//Lógica del juego
				gameRenderDoubleBuffer();	//Actualización de la imagen (Doble Buffer)
				gameRenderScreen();			//Actualización de la imagen del dispositivo de video
			}

			try{
				Thread.sleep(100); //Establece el tiempo de sueño en ms
			}catch(Exception e){}
		}
		System.out.println("======================================================================");
		System.out.println("Core Stop");
		System.out.println("======================================================================");
	}

	//==============================================================================================
	//	MÉTODOS DE LA CLASE QUE CONTROLAN LA LÓGICA DEL JUEGO
	//==============================================================================================
	/**Se lleva a cabo la lógica de actualización del juego*/
	private void gameUpdate(){
		//Verificamos si el juego no ha terminado
		if ( gameRunning ){
			//Verificamos si el juego no se encuentra pausado
			if ( gamePaused )
				gamePausedUpdate(); //Actualización para juego pausado
			else
				gameRunningUpdate();//Actualización para juego corriendo			
		}else
			gameOverUpdate();		//Actualización para juego terminado		
	}
	/**Se lleva a cabo la lógica para renderizar los objetos en una imagen, para poder implementar
		la técnica de Doble Buffer*/
	private void gameRenderDoubleBuffer(){
		//Obtenemos el Graphics del Image
		//Graphics g = gameCanvas.getImageGraphics();
		Graphics g = null;

		//Verificamos si el juego no ha terminado
		if ( gameRunning ){
			//Verificamos si el juego no se encuentra pausado
			if ( gamePaused )
				gamePausedRenderize(g);	//Renderización para juego pausado
			else
				gameRunningRenderize(g);//Renderización para juego corriendo
		}else
			gameOverRenderize(g);		//Renderización para juego terminado
	}
	/**Se renderiza la imagen creada en gameRenderDoubleBuffer() en el controlador de video*/
	private void gameRenderScreen(){
		//Obtenemos el Graphics del Canvas
		Graphics g = null;
		//Obtenemos la imagen para realizar el doble buffer
		Image image = null;

		try{
			g.drawImage(image, 0, 0, null);
			Toolkit.getDefaultToolkit().sync(); //Necesario para algunos S.O.´s
			g.dispose(); //Liberamos el objeto
		}catch(Exception e){ //Error al intentar renderizar

		}
	}
	//==============================================================================================
	//	MÉTODOS HOOK DE CONTROL DEL JUEGO Y RENDERIZADO PARA QUE EL USUARIO REDEFINA
	//==============================================================================================
	/**Controla la lógica del juego cuando el mismo está ejecutándose normalmente*/
	abstract public void gameRunningUpdate();
	/**Controla la lógica del juego cuando el mismo está pausado*/
	abstract public void gamePausedUpdate();
	/**Controla la lógica del juego cuando el mismo ha terminado*/
	abstract public void gameOverUpdate();
	/**Renderiza la pantalla cuando el juego está ejecutándose normalmente*/
	abstract public void gameRunningRenderize(Graphics g);
	/**Renderiza la pantalla cuando el juego está pausado*/
	abstract public void gamePausedRenderize(Graphics g);
	/**Renderiza la pantalla cuando el juego ha terminado*/
	abstract public void gameOverRenderize(Graphics g);	
}
